import java.util.LinkedList;

import org.jfree.data.category.DefaultCategoryDataset;

public class ChartGenerator
{
	public void constructFanOutChart(Project project, boolean relative)
	{
		ChartVersion[] chartVersions = project.getChartVersions();
		// Set chart series data for every ChartVersion we will be charting
		for (ChartVersion ver : chartVersions)
			ver.setSeriesData(getSeries(ver.getVersion(), true));
		// Set chart labels
		String title = "FanOut Histogram";
		String xAxisLabel = "FanOut";
		String yAxisLabel = "FanOut %";
		ChartWrapper cw = ChartWrapper.getInstance();
		cw.createRelativeHistogram(title, xAxisLabel, yAxisLabel, project, false, true,
				relative);
	}

	public void constructFanInChart(Project project, boolean relative)
	{
		ChartVersion[] chartVersions = project.getChartVersions();
		// Set chart series data for every ChartVersion we will be charting
		for (ChartVersion ver : chartVersions)
			ver.setSeriesData(getSeries(ver.getVersion(), false));
		// Set chart labels
		String title = "FanIn Histogram";
		String xAxisLabel = "FanIn";
		String yAxisLabel = "FanIn %";
		ChartWrapper cw = ChartWrapper.getInstance();
		cw.createRelativeHistogram(title, xAxisLabel, yAxisLabel, project, false, true,
				relative);
	}

	public void constructGrowthChart(Project project, int start, int end, int increment,
			int chartType)
	{
		String title = "defaultTitle";
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();

		LinkedList<Version> versions = project.getVersionList();

		int yAxisValue = 0;
		String yAxisCategoryLabel = "";

		for (int i = start - 1; i < end; i++)
		{
			Version ver = versions.get(i);

			yAxisValue += getYAxisValue(ver, chartType);
			yAxisCategoryLabel += versions.get(i).getReleaseSequenceNum() + " ";

			// check for increment value
			if ((i + 1) % increment == 0 || i == end - 1)
			{
				dataset.addValue(yAxisValue, "series", yAxisCategoryLabel);
				yAxisValue = 0;
				yAxisCategoryLabel = "";
			}
		}

		String xAxisLabel = "Release Sequence Number (RSN)";
		String yAxisLabel = switchChartSelection(chartType);
		title = getGraphTitle(chartType);
		
		ChartWrapper cw = ChartWrapper.getInstance();
		cw.createGrowthChart(project, title, xAxisLabel, yAxisLabel, false, true, dataset);
	}

	private int getYAxisValue(Version ver, int chartType)
	{
		LinkedList<MetricClass> metricClassList;
		switch (chartType)
		{
			// Classes.
			case 0 :
				return ver.getNumClasses();
				// Methods
			case 1 :
				int methodCount = 0;
				metricClassList = ver.getMetricClasses();
				for (MetricClass metricClass : metricClassList)
					methodCount += metricClass.getMethodCount();
				return methodCount;
				// Packages
			case 2 :
				return ver.getPackageCount();
				// Byte Code
			case 3 :
				double byteCodeCount = 0;
				metricClassList = ver.getMetricClasses();
				for (MetricClass metricClass : metricClassList)
					byteCodeCount += metricClass.getByteCodeSizeInKb();
				return (int) (byteCodeCount * 1000);
		}
		return -1; // fail
	}

	private String getGraphTitle(int chartSelection)
	{

		String graphTitle = "";
		switch (chartSelection)
		{
			// Classes.
			case 0 :
				graphTitle = "Growth by Classes";
				break;
			// Methods
			case 1 :
				graphTitle = "Growth by Methods";
				break;
			// Packages
			case 2 :
				graphTitle = "Growth by Packages";
				break;
			// Byte Code
			case 3 :
				graphTitle = "Growth by Byte-Code";
				break;
		}
		return graphTitle;
	}

	/**
	 * @param chartSelection
	 * @return
	 */
	private String switchChartSelection(int chartSelection)
	{
		String yAxisLabel = "";
		switch (chartSelection)
		{
			// Classes.
			case 0 :
				yAxisLabel = "# classes";
				break;
			// Methods
			case 1 :
				yAxisLabel = "# methods";
				break;
			// Packages
			case 2 :
				yAxisLabel = "# packages";
				break;
			// Byte Code
			case 3 :
				yAxisLabel = "# byte-code";
				break;
		}
		return yAxisLabel;
	}

	/**
	 * Generates histogram data for the specified version
	 * @param version - The version.
	 * @return - A hashtable containing the cumalative fanout results.
	 */

	private double[] getSeries(Version version, boolean fanOut)
	{
		LinkedList<MetricClass> metricClasses = version.getMetricClasses();
		double[] ret = new double[metricClasses.size()];

		int index = 0;
		for (MetricClass mc : metricClasses)
		{
			if (fanOut)
				ret[index++] = mc.getFanOutCount();
			else
				ret[index++] = mc.getFanInCount();
		}
		return ret;
	}

}
